跳到主要内容

Proxy 与 Reflect 的使用

如果说 Object.defineProperty 是对象的属性代理,

ProxyReflect 就是针对整个对象的代理。

通过使用这两个函数,我们可以对对象进行更精细,复杂的劫持。

Proxy 语法以及参数

const p = new Proxy(target, handler);
参数说明
target要使用 Proxy 包装的目标对象
(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。
handler一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p 的行为。

handler 的方法

如果定义了相应的劫持器,则当调用相应 API 的时候会触发该劫持器,如果没定义则会保持默认

Proxy 函数方法含义
getPrototypeOf 对应 Object.getPrototypeOf 方法的捕捉器Object.getPrototypeOf 为获取对象的原型
setPrototypeOf 对应 Object.setPrototypeOf 方法的捕捉器Object.setPrototypeOf 为设置对象的原型
isExtensible 对应 Object.isExtensible 方法的捕捉器Object.isExtensible 为检测该对象是否是可拓展的,即是否可以添加新属性。
preventExtensions 对应 Object.preventExtensions 方法的捕捉器Object.preventExtensions 会让传入的对象变成不可拓展对象,即不能添加新的属性
getOwnPropertyDescriptor 对应 Object.getOwnPropertyDescriptor 方法的捕捉器Object.getOwnPropertyDescriptor 为获取对象属性的描述符,与 Object.defineProperty 所设置的描述符一致
defineProperty 对应 Object.defineProperty 方法的捕捉器Object.defineProperty 会修改对象的属性以及描述符,使其修改原属性或新增属性
has 对应 in 运算符的捕捉器当指定的属性在指定的对象或其原型链中,调用 in 运算符会返回 true
get 对应属性读取操作的捕捉器属性读取操作的捕捉器
set 对应属性设置操作的捕捉器属性设置操作的捕捉器
ownKeys 对应 Object.getOwnPropertyNames 方法和 Object.getOwnPropertySymbols 方法的捕捉器。Object.getOwnPropertyNames 为返回自身的所有属性的属性名,而 Object.getOwnPropertySymbols 返回的是 Symbol 属性数组,Symbol 代表一个独一无二的值
apply 对应函数调用操作的捕捉器如果对 proxy 进行调用会触发该捕捉器
construct 对应 new操作符的捕捉器。当对 proxy 进行 new 操作时会触发该捕捉器
handler 的约束问题

Proxy 的捕捉器函数存在一定的约束,具体可以在 MDN 查询,核心观点其实就是单纯的不允许 Proxy 代理的对象与原对象不一致,如原对象是不可拓展的,那就不可以在 Proxy 返回可拓展,否则就违背了原对象的含义。

Reflect 介绍

ReflectProxy 都同时在 ES2015 标准中,算是与 Proxy 一起的伴生 API

他是一个内置的对象,提供的方法与 ProxyHandler 中是相同的。

但是他不是一个函数,因此是不可构造的,我们只可以使用他的静态方法。

为什么存在 Reflect

通常我们将它与 Proxy 进行联合使用,在进行劫持后调用原方法,那为什么不直接操作对象呢?

这点我认为存在两个原因

  1. 目前暴露了一些核心的 api 供我们调用,但是未来可能隐藏掉这些 api,通过 Reflect 才能调用。

  2. 统一操作的过程,如果我们不使用 Reflect 提供的函数,而使用操作的函数进行对象操作,那有一部分对象操作失败会报出异常,有一部分会报出 null 等等,返回值并不统一,而 Reflect 相对统一,比如曾经错误会报出异常的函数,在 Reflect 内会返回 false,使用 Reflect 我们可以对各种函数有一个更统一的返回值以及处理。

Reflect 的函数有哪些?

Reflect 函数方法含义
Reflect.apply(target, thisArgument, argumentsList)对一个函数进行调用操作,同时可以传入一个数组作为调用参数。和 Function.prototype.apply() 功能类似。
Reflect.construct(target, argumentsList[, newTarget])对构造函数进行 new 操作,相当于执行 new target(...args)
Reflect.defineProperty(target, propertyKey, attributes)Object.defineProperty() 类似。如果设置成功就会返回 true
Reflect.deleteProperty(target, propertyKey)函数的 delete 操作符,相当于执行 delete target[name]
Reflect.get(target, propertyKey[, receiver])获取对象身上某个属性的值,类似于 target[name]
Reflect.getOwnPropertyDescriptor(target, propertyKey)类似于 Object.getOwnPropertyDescriptor()。如果对象中存在该属性,则返回对应的属性描述符, 否则返回 undefined
Reflect.getPrototypeOf(target)Object.getPrototypeOf 获取对象的原型的函数行为类似
Reflect.has(target, propertyKey)判断一个对象是否存在某个属性,和 in 运算符 的功能完全相同
Reflect.isExtensible(target)类似于 Object.isExtensible(),判断对象是否是可拓展的对象
Reflect.ownKeys(target)返回一个包含所有自身属性(不包含继承属性)的数组。(类似于 Object.keys(), 但不会受 enumerable 影响)
Reflect.preventExtensions(target)类似于 Object.preventExtensions(), 让传入的对象变成不可拓展对象
Reflect.set(target, propertyKey, value[, receiver])将值分配给属性的函数,返回一个 Boolean,等价于属性赋值
Reflect.setPrototypeOf(target, prototype)设置对象原型的函数,返回一个 Boolean